package org.ascollada.core
{
	import flash.errors.IllegalOperationError;
	
	import org.ascollada.core.ns.collada;
	import org.ascollada.utils.DaeLogger;
	
	public class DaeSkin extends DaeElement
	{
		use namespace collada;
		
		/**
		 * 
		 */ 
		public var source :String;
		
		/**
		 * 
		 */ 
		public var bind_shape_matrix :DaeMatrix;
		
		/**
		 * 
		 */ 
		public var joints :Array;
		
		/**
		 * 
		 */ 
		public var inv_bind_matrix :Array;
		
		/**
		 * 
		 */ 
		public var vertex_weights :Array;
		
		/**
		 * 
		 */ 
		public function DaeSkin(document:DaeDocument, element:XML=null)
		{
			super(document, element);
		}
		
		/**
		 * 
		 */ 
		public function getJointIndex(id:String):int
		{
			var index :int = -1;
			for(var i:int = 0; i < joints.length; i++)
			{
				if(id == joints[i])
					return i;
			}
			return index;
		}
		
		/**
		 * 
		 */ 
		public function getWeightsForJoint(id:String):Array
		{
			var w :Array = new Array();
			for(var i:int = 0; i < vertex_weights.length; i++)
			{
				for(var j:int = 0; j < vertex_weights[i].length; j++)
				{
					var bw :DaeBlendWeight = vertex_weights[i][j];
					if(bw.joint == id)
						w.push(bw);
				}
			}
			return w;
		}
		
		/**
		 * @inheritDoc
		 */ 
		public override function read(element:XML):void
		{
			super.read(element);
			
			this.source = readAttribute(element, "source", true);
			
			// bind shape matrix
			if(element.bind_shape_matrix[0])
				this.bind_shape_matrix = new DaeMatrix(readStringArray(element.bind_shape_matrix[0]));
			else
				this.bind_shape_matrix = new DaeMatrix();
			
			readJoints(element.joints[0]);
			readWeights(element.vertex_weights[0]);
		}
		
		/**
		 * 
		 */ 
		private function readJoints(element:XML):void
		{
			if(!element)
			{
				throw new IllegalOperationError("DaeSkin expects a single <joints> element!");
			}
			
			var a :XML = element.input.(@semantic == "JOINT")[0];
			var b :XML = element.input.(@semantic == "INV_BIND_MATRIX")[0];
			
			if(!a || !b)
			{
				throw new IllegalOperationError("DaeSkin <joints> element misses a required <input> element!");
			}
			
			var ainput :DaeInput = new DaeInput(null, a);
			var binput :DaeInput = new DaeInput(null, b);
			
			var asource :DaeSource = document.sources[ainput.source];
			var bsource :DaeSource = document.sources[binput.source];
			var i :int;
			
			this.joints = asource.data;
			this.inv_bind_matrix = new Array();
			
			for(i = 0; i < bsource.data.length; i++)
			{
				this.inv_bind_matrix.push(new DaeMatrix(bsource.data[i]));	
			}
		}
		
		/**
		 * 
		 */ 
		private function readWeights(element:XML):void
		{
			if(!element)
			{
				throw new IllegalOperationError("DaeSkin expects a single <vertex_weights> element!");
			}
			
			var count :uint = parseInt(readAttribute(element, "count"), 10);
			
			var a :XML = element.input.(@semantic == "JOINT")[0];
			var b :XML = element.input.(@semantic == "WEIGHT")[0];
			
			if(!a || !b)
			{
				throw new IllegalOperationError("DaeSkin <vertex_weights> element misses a required <input> element!");
			}
			
			var ainput :DaeInput = new DaeInput(null, a);
			var binput :DaeInput = new DaeInput(null, b);
			
			var asource :DaeSource = document.sources[ainput.source];
			var bsource :DaeSource = document.sources[binput.source];
			var inputCount :uint = element.input.length();
			var i :int, j:int;

			if(!element.v[0])
			{
				DaeLogger.log("DaeSkin : <vertex_weights> elements does not have a <v> element!");
				return;
			}
			
			if(!element.vcount[0])
			{
				DaeLogger.log("DaeSkin : <vertex_weights> elements does not have a <v> element!");
				return;
			}
			
			var v:Array = readStringArray(element.v[0]);
			var vcount :Array = readStringArray(element.vcount[0]);
			var cur :int = 0;
			
			this.vertex_weights = new Array();
			
			for(i = 0; i < vcount.length; i++)
			{
				var vc:int = vcount[i];
				
				var tmp:Array = new Array();
					
				for(j = 0; j < vc; j++)
				{
					var jidx:int = v[cur + ainput.offset];
					var widx:int = v[cur + binput.offset];
					
					var weight :Number = bsource.data[widx];
					
					tmp.push(new DaeBlendWeight(i, joints[jidx], weight));
				
					cur += inputCount;
				}
				
				this.vertex_weights.push(tmp);
			}
		}
	}
}